#include "common/common.h"
#include "Core/TCFixedString.h"
#include "string/stringoutput.h"
#include "Core/TCSimpleDynamicArray.h"
#include "testlibpilo.h"

using namespace PILO::Core::Containers;
using namespace PILO::Core::String;
using namespace PILO::Core::Memory;

static INT32 case_TCSimpleDynamicArray_Operator_Equal(void* param);
static INT32 case_TCSimpleDynamicArray_CopyConstructor(void* param);
static INT32 case_TCSimpleDynamicArray_ConstInternalData(void* param);
static INT32 case_TCSimpleDynamicArray_ConstAt(void *param);
static INT32 case_TCSimpleDynamicArray_Operator_Index(void* param);
static INT32 case_TCSimpleDynamicArray_append(void* param);
static INT32 case_TCSimpleDynamicArray_takeLast(void* param);
static INT32 case_TCSimpleDynamicArray_prepend(void* param);
static INT32 case_TCSimpleDynamicArray_takeFirst(void* param);
static INT32 case_TCSimpleDynamicArray_indexOf(void* param);
static INT32 case_TCSimpleDynamicArray_lastIndexOf(void* param);
static INT32 case_TCSimpleDynamicArray_removeAt(void* param);
static INT32 case_TCSimpleDynamicArray_removeOne(void* param);
static INT32 case_TCSimpleDynamicArray_removeAll(void* param);
static INT32 case_TCSimpleDynamicArray_insert(void* param);
static INT32 case_TCSimpleDynamicArray_attach_detach(void* param);



static case_testing_t g_cases_PILOTSimpleDynamicSortedArray[] = {
    {1,  "TCSimpleDynamicArray::operator=                   ", 0,  case_TCSimpleDynamicArray_Operator_Equal,           -1},
    {2,  "TCSimpleDynamicArray copy constructor             ", 0,  case_TCSimpleDynamicArray_CopyConstructor,          -1},
    {3,  "TCSimpleDynamicArray::internalData                ", 0,  case_TCSimpleDynamicArray_ConstInternalData,        -1},
    {4,  "TCSimpleDynamicArray::at                          ", 0,  case_TCSimpleDynamicArray_ConstAt,                  -1},
    {5,  "TCSimpleDynamicArray::operator[]                  ", 0,  case_TCSimpleDynamicArray_Operator_Index,           -1},
    {6,  "TCSimpleDynamicArray::append                      ", 0,  case_TCSimpleDynamicArray_append,                   -1},
    {7,  "TCSimpleDynamicArray::takeLast                    ", 0,  case_TCSimpleDynamicArray_takeLast,                 -1},
    {8,  "TCSimpleDynamicArray::prepend                     ", 0,  case_TCSimpleDynamicArray_prepend,                  -1},
    {9,  "TCSimpleDynamicArray::takeFirst                   ", 0,  case_TCSimpleDynamicArray_takeFirst,                -1},
    {10, "TCSimpleDynamicArray::indexOf                     ", 0,  case_TCSimpleDynamicArray_indexOf,                  -1},
    {11, "TCSimpleDynamicArray::lastIndexOf                 ", 0,  case_TCSimpleDynamicArray_lastIndexOf,              -1},
    {12, "TCSimpleDynamicArray::removeAt                    ", 0,  case_TCSimpleDynamicArray_removeAt,                 -1},
    {13, "TCSimpleDynamicArray::removeOne                   ", 0,  case_TCSimpleDynamicArray_removeOne,                -1},
    {14, "TCSimpleDynamicArray::removeAll                   ", 0,  case_TCSimpleDynamicArray_removeAll,                -1},
    {15, "TCSimpleDynamicArray::insert                      ", 0,  case_TCSimpleDynamicArray_insert,                   -1},
    {16, "TCSimpleDynamicArray::attach/detach               ", 0,  case_TCSimpleDynamicArray_attach_detach,            -1},


};



static INT32 g_id = 0;

INT32 test_TCSimpleDynamicArray_Functional(INT32 id, BOOL breakOnErrorOccured)
{
    g_id = id;

    FormatOutputToConsole("Testing Part_%d <pilotsimpledynamicarray.h>\n", id);

    int i=0;
    for (i=0; i<MCF_COUNT_OF(g_cases_PILOTSimpleDynamicSortedArray); i++) {
        case_testing_t * caseParam = &g_cases_PILOTSimpleDynamicSortedArray[i];
        ASSERT(caseParam != NULL);
        FormatOutputToConsole(" #[%03d.%03d]: Testing %s",g_id, caseParam->ct_id, caseParam->ct_decription);

        caseParam->ct_result = caseParam->ct_function(static_cast<case_testing_t *>(caseParam));
        if (caseParam->ct_result == 0) { //ok
            FormatOutputToConsole("[PASSED]\n");
        } else {
            FormatOutputToConsole("[FAILED:%d]\n",caseParam->ct_result);
            if (breakOnErrorOccured) {
                ASSERT(FALSE);
            }
        }
    }


    FormatOutputToConsole("Result of Part_%d <pilotsimpledynamicarray.h> total  %d, failed %d\n\n",id, MCF_COUNT_OF(g_cases_PILOTSimpleDynamicSortedArray), failedOFCases(g_cases_PILOTSimpleDynamicSortedArray,MCF_COUNT_OF(g_cases_PILOTSimpleDynamicSortedArray)));
    return 0;
}


static INT32 case_TCSimpleDynamicArray_Operator_Equal(void*)
{
    TestElement element;

    TCSimpleDynamicArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicArray(arraySrc, 100, "FOX");
    if (arraySrc.size() != 100) {
        return -1;
    }
    char checkBuf[32];
    for (int i=0; i<100; i++)
    {
        FormatOutputToString(checkBuf, MCF_COUNT_OF(checkBuf), "FOX @ %010d", i);
        TestElement elementTmp(i, checkBuf );

        if (arraySrc.at(i) != elementTmp) {
            return -1*100;
        }
    }

    TCSimpleDynamicArray<TestElement, 1, 5> arrayDest;
    arrayDest = arraySrc;
    if (arrayDest.size() != 100) {
        return -1;
    }
    for (int i=0; i<100; i++)
    {
        FormatOutputToString(checkBuf, MCF_COUNT_OF(checkBuf), "FOX @ %010d", i);
        TestElement elementTmp(i, checkBuf );

        if (arraySrc.at(i) != elementTmp) {
            return -1*200;
        }
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_CopyConstructor(void*)
{
    TestElement element;

    TCSimpleDynamicArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicArray(arraySrc, 100, "FOX");
    //check this array
    if (arraySrc.size() != 100) {
        return -1;
    }
    char checkBuf[32];
    for (int i=0; i<100; i++)
    {
        FormatOutputToString(checkBuf, MCF_COUNT_OF(checkBuf), "FOX @ %010d", i);
        TestElement elementTmp(i, checkBuf );

        if (arraySrc.at(i) != elementTmp) {
            return -1*100;
        }
    }

    TCSimpleDynamicArray<TestElement, 1, 5> arrayDest(arraySrc);
    if (arrayDest.size() != 100) {
        return -1;
    }
    for (int i=0; i<100; i++)
    {
        FormatOutputToString(checkBuf, MCF_COUNT_OF(checkBuf), "FOX @ %010d", i);
        TestElement elementTmp(i, checkBuf );

        if (arraySrc.at(i) != elementTmp) {
            return -1*200;
        }
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_ConstInternalData(void *)
{
    char buf[30];
    char compareBuffer[sizeof(TestElement)*100];
    memset(compareBuffer,0x00, sizeof(TestElement)*100);
    size_t index = 0;
    TestElement element;
    TCSimpleDynamicArray<TestElement, 1, 5> arraySrc;
    // fill this array
    for (int i=0; i<100; i++) {
        element.setID(i);
        memcpy(compareBuffer+index, &i, sizeof(i));
        index += sizeof(i);

        size_t checkLen = FormatOutputToString(buf, MCF_COUNT_OF(buf), "FOX @ %010d", i);
        if (checkLen != StringLength(buf)) {
            return -1;
        }
        element.setData(buf);
        memcpy(compareBuffer+index, buf, checkLen);
        index += 32;

        arraySrc.append(element);
    }

    if ( memcmp(arraySrc.constInternalData(), compareBuffer, sizeof(TestElement)*100) != 0) {
        return -2;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_ConstAt(void *)
{
    TCSimpleDynamicArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicArray(arraySrc, 100, "PeT");

    const TestElement&  elementValid = arraySrc.at(99);
    TestElement ele1;
    ele1.set(99,"PeT");
    if (elementValid != ele1) {
        return -1;
    }

    if (arraySrc.exist(100) != MC_NULLPTR_OF_(TestElement*)) {
        return -2;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_Operator_Index(void* )
{
    TCSimpleDynamicArray<TestElement, 100, 5> arraySrc;
    TMakeSampleDynamicArray(arraySrc, 10, "PeT");

    TestElement element;
    element.setID(20);
    element.setData("FUCK");
    arraySrc[20] = element;

    if(arraySrc.at(20) != element) {
        return -2;
    }

    for (size_t idx=10; idx<20; idx++) {
        if(arraySrc.at(19) != _type_default_value_<TestElement>::get()) {
            return  (0-(100+(INT32)idx));
        }
    }


    return 0;
}

static INT32 case_TCSimpleDynamicArray_append(void* )
{
    TCSimpleDynamicArray<TestElement, 1, 7> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 8, "APP");
    //TDebugOutputArray(arrayTest);

    //testing base push function
    TestElement ele1(7, "APP @ 0000000007");
    if ((arrayTest.at(7) != ele1) || (arrayTest.size() != 8) || (arrayTest.capacity() != 8)) {
        return -1;
    }

    //testing inflation
    ele1.setID(8);
    ele1.setData("Fucker_1");
    TestElement ele2 = ele1;
    arrayTest.append(ele1);

    ASSERT(ele1 == ele2);
    if ((arrayTest.at(8) != ele2) || (arrayTest.size()!=9) || (arrayTest.capacity()!=15)) {
        return -2;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_takeLast( void*  )
{
    TCSimpleDynamicArray<TestElement, 1, 7> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 8, "TKL");

    TestElement element = arrayTest.takeLast();
    TestElement ele1(7, "TKL @ 0000000007");
    if ((element != ele1) || (arrayTest.size() != 7) || (arrayTest.capacity() != 8)) {
        return -1;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_prepend( void*  )
{
    TCSimpleDynamicArray<TestElement, 1, 7> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 8, "PRP");

    TestElement ele1;
    ele1.setID(8);
    ele1.setData("Fucker_0");
    TestElement ele2 = ele1;
    arrayTest.preappend(ele1);
    
    if (arrayTest.size()!=9) {
        return -2;
    }
    if (arrayTest.capacity()!=15) {
        return -3;
    }

    if (arrayTest[0] != ele2) {
        return -4;
    }

    //TDebugOutputArray(arrayTest);

    return 0;
}


static INT32 case_TCSimpleDynamicArray_takeFirst( void*  )
{
    TCSimpleDynamicArray<TestElement, 1, 100> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 100, "TKF");
    //TDebugOutputArray(arrayTest);

    INT32 i=0;
    while(! arrayTest.isEmpty()) {

        TestElement cmpElement;
        cmpElement.set(i, "TKF");

        TestElement firstElement = arrayTest.takeFirst();

        if (firstElement != cmpElement) {
            return -2;
        }

        i++;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_indexOf( void*  )
{
    TCSimpleDynamicArray<TestElement, 1, 100> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 100, "IDO");

    TestElement cmpElement;
    cmpElement.set(57, "IDO");

    size_t ind = arrayTest.indexOf(cmpElement);
    if (ind != 57) {
        return -1;
    }

    ind = arrayTest.indexOf(cmpElement,56);
    if (ind != 57) {
        return -2;
    }

    ind = arrayTest.indexOf(cmpElement, 57, 1);
    if (ind != 57) {
        return -3;
    }

    ind = arrayTest.indexOf(cmpElement, 58, 1);
    if (ind != MC_INVALID_SIZE) {
        return -4;
    }

    ind = arrayTest.indexOf(cmpElement, 58);
    if (ind != MC_INVALID_SIZE) {
        return -5;
    }

    ind = arrayTest.indexOf(cmpElement,56, 90000);
    if (ind != 57) {
        return -6;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_lastIndexOf( void*  )
{
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 10, "LIO");

    TestElement cmpElement;
    cmpElement.set(7, "LIO");

    size_t rind = arrayTest.lastIndexOf(cmpElement);
    if (rind != 7) {
        return -1;
    }

    rind = arrayTest.lastIndexOf(cmpElement,7, 1);
    if (rind != 7) {
        return -1;
    }

    rind = arrayTest.lastIndexOf(cmpElement,6, 1);
    if (rind != MC_INVALID_SIZE) {
        return -1;
    }

    rind = arrayTest.lastIndexOf(cmpElement,6, 6);
    if (rind != MC_INVALID_SIZE) {
        return -1;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_removeAt(void*)
{
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 10, "REM");

    arrayTest.removeAt(9);
    arrayTest.removeAt(7);
    arrayTest.removeAt(0);

    if (arrayTest.count() != 7) {
        return -1;
    }
    TestElement ele1;
    ele1.set(1,"REM");
    if (arrayTest[0] != ele1) {
        return -2;
    }

    for(int i=0;i<7;i++) {
        arrayTest.removeAt(0);
    }
    if (arrayTest.count() != 0) {
        return -3;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_removeOne( void* )
{
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 10, "RM1");
    
    TestElement ele1;
    ele1.set(1,"RM1");
    arrayTest.preappend(ele1);
    arrayTest.append(ele1);

    BOOL founded = arrayTest.removeOne(ele1);
    if (! founded) {
        return -1;
    }

    if (arrayTest[10] != ele1) {
        return -1;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicArray_removeAll(void* )
{
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 10, "RMA");
    

    TestElement ele1;
    ele1.set(1,"RMA");
    arrayTest.preappend(ele1);
    arrayTest.append(ele1);
    arrayTest.preappend(ele1);
    arrayTest.append(ele1);

    //TDebugOutputArray(arrayTest);

    if (arrayTest.count() != 14) {
        return -1;
    }

    size_t numfound = arrayTest.removeAll(ele1);
    if (5 != numfound) {
        return -2;
    }

    arrayTest.clear();
    TMakeSampleDynamicArray(arrayTest, 10, "RMA");
    arrayTest.preappend(ele1);
    arrayTest.append(ele1);
    arrayTest.preappend(ele1);
    arrayTest.append(ele1);
    if (arrayTest.count() != 14) {
        return -1;
    }
    numfound = arrayTest.removeAll(ele1,3);
    if (3 != numfound) {
        return -3;
    }
    return 0;
}

static INT32 case_TCSimpleDynamicArray_insert( void*  )
{
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicArray(arrayTest, 10, "INS");

    TestElement ins1;
    ins1.set(2,"ins");
    arrayTest.insert(2, ins1);

    if (arrayTest[2] != ins1) {
        return -1;
    }

   // TDebugOutputArray(arrayTest);


    return 0;
}

static INT32 case_TCSimpleDynamicArray_attach_detach( void*  )
{
    TestElement arrayData[100];
    arrayData[0].set(0,"ATT");
    TCSimpleDynamicArray<TestElement, 10, 1> arrayTest;
    arrayTest.attach(arrayData,100,1);

    for (int index=1; index<100; index++) {
        arrayTest[index].set(index, "ATT");
    }

    if (arrayTest.count() != 100) {
        return -1;
    }

    for (int i=0; i<100; i++) {
        TestElement ele1;
        ele1.set(i,"ATT");

        if (arrayTest.at(i) != ele1) {
            return -2;
        }
    }

    arrayTest.detach();

    if (arrayTest.count()!=0) {
        return -3;
    }
    if (arrayTest.capacity() != 0) {
        return -4;
    }
    if (!arrayTest.isMemoryOwner()) {
        return -5;
    }
    if (arrayTest.constInternalData() != MC_NULLPTR_OF_(TestElement*)) {
        return -6;
    }

    //TDebugOutputArray(arrayTest);

    return 0;
}

